home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacHack 1996
/
MacHack 1996.toast
/
Presentations
/
Presentations ’93
/
Macintosh as Internet Server ƒ
/
inetd
/
in.rshd
/
in.rcp
/
rcp.cp
< prev
next >
Wrap
Text File
|
1993-04-08
|
12KB
|
593 lines
//---------------------------------------------------------------------
//
// Copyright © 1992 David Peterson.
// All rights reserved.
//
// Permission to use, copy, modify, and distribute this software for
// any purpose and without fee is hereby granted, provided that the
// above copyright notice appear in all copies and that both that
// copyright notice and this permission notice appear in supporting
// documentation.
//
//---------------------------------------------------------------------
#include "rcp.h"
#include <UFailure.h>
#include <myUtils.h>
#include <TCP.h>
#include <Sysequ.h>
#include <Folders.h>
#include <Packages.h>
#include <String.h>
#include <Strings.h>
#include <Errors.h>
#include <OSEvents.h>
#include <StdLib.h>
#include <ToolUtils.h>
#include <CType.h>
#include <Devices.h>
#include <Resources.h>
#include <StdIO.h>
void main();
void
main()
{
Rcp* aDaemon;
InitUDaemonApp(*((long*) DefltStack));
aDaemon = new Rcp;
if (aDaemon) {
aDaemon->Initialize();
aDaemon->Run();
{
AppleEvent theEvent;
AEDesc theAddress;
long theType = 'inet';
OSErr theErr = noErr;
AECreateDesc(typeApplSignature, (Ptr) &theType, sizeof(theType), &theAddress);
AECreateAppleEvent(kCoreEventClass, kAEApplicationDied, &theAddress, kAutoGenerateReturnID, kAnyTransactionID, &theEvent);
AEPutParamPtr(&theEvent, keyErrorNumber, typeLongInteger, (Ptr) &theErr, sizeof(long));
AEPutParamPtr(&theEvent, keyProcessSerialNumber, typeProcessSerialNumber, (Ptr) &(aDaemon->fPSN), sizeof(ProcessSerialNumber));
DebugIfErr(AESend(&theEvent, nil, kAENoReply, kAEHighPriority, 0, nil, nil));
}
delete aDaemon;
}
}
Rcp::Rcp()
{
fFileSize = 0;
fAmtLeft = 0;
fWorkingOnAFile = false;
fFileIORefNum = 0;
fTargetShouldBeDir = false;
fTargetIsDir = false;
fIAmRecursive = false;
fToFlag = false;
fFromFlag = false;
fVRefNum = 0;
fDirID = 0;
fFileName[0] = 0;
fBuffer = nil;
}
Rcp::~Rcp()
{
tcpClose(fStreamPtr);
if (fBuffer) DisposePtr(fBuffer);
}
void
Rcp::InstallAEHandlers()
{
Inherited::InstallAEHandlers();
FailOSErr(AEInstallEventHandler('INET', 'TSTR',
(EventHandlerProcPtr) &AEStreamHandler, (long) this, false));
}
void
Rcp::Initialize()
{
Inherited::Initialize();
Handle h;
int size;
h = GetResource('BUFF', 128);
if (h)
size = *((int*) *h);
else
size = 2048;
fBuffer = NewPtr(size);
fBufLen = size;
}
pascal OSErr
AEStreamHandler(AppleEvent* messagein, AppleEvent* /*reply*/, long refIn)
{
OSErr theErr = noErr;
Rcp* daemon = (Rcp*) refIn;
AEDesc streamDesc, commandDesc;
if ((theErr = AEGetParamDesc(messagein, 'STRM', typeLongInteger, &streamDesc)) == noErr) {
HLock(streamDesc.dataHandle);
daemon->fStreamPtr = *((StreamPtr*) *(streamDesc.dataHandle));
HUnlock(streamDesc.dataHandle);
AEDisposeDesc(&streamDesc);
}
if ((theErr = AEGetParamDesc(messagein, 'CMND', typeChar, &commandDesc)) == noErr) {
HLock(commandDesc.dataHandle);
BlockMove(*(commandDesc.dataHandle), daemon->fCommandString, 256);
HUnlock(commandDesc.dataHandle);
AEDisposeDesc(&commandDesc);
}
daemon->TakeControlOfStream();
daemon->ParseCommandString();
return theErr;
}
void
Rcp::TakeControlOfStream()
{
AppleEvent theEvent, myReply;
AEDesc theAddress;
long theType = 'inet';
ProcPtr theProc = (ProcPtr) &Notify;
Rcp* daemon = this;
AECreateDesc(typeApplSignature, (Ptr) &theType, sizeof(theType), &theAddress);
AECreateAppleEvent('INET', 'TNFY', &theAddress, kAutoGenerateReturnID, kAnyTransactionID, &theEvent);
AEPutParamPtr(&theEvent, 'STRM', typeLongInteger, (Ptr) &fStreamPtr, sizeof(StreamPtr));
AEPutParamPtr(&theEvent, 'ASR ', typeLongInteger, (Ptr) &theProc, sizeof(ProcPtr));
AEPutParamPtr(&theEvent, 'USRP', typeLongInteger, (Ptr) &daemon, sizeof(long));
AEPutParamPtr(&theEvent, keyProcessSerialNumber, typeProcessSerialNumber, (Ptr) &fPSN, sizeof(ProcessSerialNumber));
FailOSErr(AESend(&theEvent, &myReply, kAEWaitReply + kAENeverInteract, kAEHighPriority, 120, nil, nil));
FailOSErr(AEDisposeDesc(&myReply));
AEDisposeDesc(&theEvent);
AEDisposeDesc(&theAddress);
}
void
Rcp::ParseCommandString()
{
char* cp;
short vRefNum;
long dirID;
// MBPrintf("rcp: got: %s", fCommandString);
cp = fCommandString;
cp += 4; // skip over 'rcp ', now pointing to first dash
while (*cp++ == '-') { // points to option char now
switch (*cp++) { // points to space after option char
case 'p':
this->SendError("rcp: sorry, remote can't handle -p");
return;
case 'f':
this->SendError("rcp: sorry, can't fetch from here (yet)");
return;
fFromFlag = true;
break;
case 'd':
fTargetShouldBeDir = true;
break;
case 'r':
fIAmRecursive = true;
fTargetShouldBeDir = true;
break;
case 't':
fToFlag = true;
break;
default:
this->SendError("rcp: unknown option");
return;
}
cp++; // points to next dash (if it exists)
}
cp--; // back up one (because next dash didn't exist)
if (fToFlag && fFromFlag) {
this->SendError("rcp: don't do that");
return;
}
else if (fToFlag) {
fMore = (rcpProc) &Rcp::GetMore;
fFile = (rcpProc) &Rcp::NewFile;
}
else {
fMore = (rcpProc) &Rcp::ReadMore;
fFile = (rcpProc) &Rcp::OpenNext;
}
this->VerifyAndSetDir(cp);
HGetVol(nil, &vRefNum, &dirID);
fVRefNum = vRefNum;
fDirID = dirID;
this->SetSleepValue(1);
this->SendOK();
}
void
Rcp::VerifyAndSetDir(char* targ)
{
long dirID;
short refNum;
char* targp;
Boolean ondesk;
OSErr theErr;
char err[128];
FSSpec spec;
FSSpec spare;
CInfoPBRec catinfo;
Boolean isdir;
char copy[128];
char* copyp;
if ((targ[0] == '.') && (targ[1] == '\0')) {
FindFolder(kOnSystemDisk, kDesktopFolderType, false, &refNum, &dirID);
HSetVol(nil, refNum, dirID);
return;
}
targp = targ;
copyp = ©[1];
while (*targp) {
switch (*targp) {
case '/':
*copyp = ':';
break;
case ':':
*copyp = '/';
break;
case '*':
case '?':
sprintf(err, "rcp: %s: wildcards not allowed", targ);
this->SendError(err);
return;
default:
*copyp = *targp;
}
copyp++;
targp++;
}
*copyp = 0;
copyp = ©[1];
if (*copyp == ':') {
copyp++;
ondesk = false;
}
else {
*(--copyp) = ':';
ondesk = true;
}
c2pstr(copyp);
// MBPrintf("copyp = %P", copyp);
if (ondesk) {
FindFolder(kOnSystemDisk, kDesktopFolderType, false, &refNum, &dirID);
theErr = FSMakeFSSpec(refNum, dirID, (Str255) copyp, &spec);
}
else
theErr = FSMakeFSSpec(0, 0, (Str255) copyp, &spec);
// MBPrintf("spec = %P, %d, %d, err = %d", spec.name, spec.vRefNum, spec.parID, theErr);
switch (theErr) {
case fnfErr:
if (fToFlag) {
BlockMove(spec.name, fFileName, spec.name[0] + 1);
HSetVol(nil, spec.vRefNum, spec.parID);
return;
}
/* fall through if we're not recipient */
case dirNFErr:
case nsvErr:
sprintf(err, "rcp: %s: No such file or directory", targ);
this->SendError(err);
break;
case noErr:
FSMakeFSSpec(spec.vRefNum, spec.parID, spec.name, &spare);
catinfo.hFileInfo.ioNamePtr = spare.name;
catinfo.hFileInfo.ioVRefNum = spare.vRefNum;
catinfo.hFileInfo.ioDirID = spare.parID;
catinfo.hFileInfo.ioFDirIndex = 0;
PBGetCatInfoSync(&catinfo);
isdir = BitTst(&catinfo.hFileInfo.ioFlAttrib, 3);
if (isdir) {
if (fToFlag)
HSetVol(spec.name, spec.vRefNum, spec.parID);
else if (fFromFlag && fIAmRecursive) {
HSetVol(nil, spec.vRefNum, spec.parID);
BlockMove(spec.name, fFileName, spec.name[0] + 1);
}
else {
sprintf(err, "rcp: %s: not a plain file", targ);
this->SendError(err);
return;
}
}
else {
if (fToFlag && fTargetShouldBeDir) {
sprintf(err, "rcp: %s: Not a directory", targ);
this->SendError(err);
}
else {
HSetVol(nil, spec.vRefNum, spec.parID);
BlockMove(spec.name, fFileName, spec.name[0] + 1);
}
}
break;
default:
sprintf(err, "rcp: %s: produced error", targ);
this->SendError(err);
break;
}
}
void
Rcp::DoNull()
{
if (fWorkingOnAFile)
fMore(this);
else
fFile(this);
}
void
Rcp::GetMore()
{
Ptr buf = fBuffer;
short len = (short) fBufLen;
len = ((fAmtLeft < len) ? fAmtLeft : len);
if (tcpRead(fStreamPtr, buf, &len) == noErr) {
fAmtLeft -= len;
this->WriteToFile(buf, len);
if (fAmtLeft == 0) {
len = 1;
tcpRead(fStreamPtr, buf, &len);
FSClose(fFileIORefNum);
fWorkingOnAFile = false;
this->SendOK();
}
}
}
void
Rcp::ReadMore()
{
}
void
Rcp::NewFile()
{
// need to get description line
// 5 chars for file type/mode then space
// file size in bytes (in ascii) then space
// file name then newline
short len = 128;
Ptr cp = fBuffer;
char type = 0;
int size = 0;
tcpRead(fStreamPtr, cp, &len);
// cp[len + 1] = 0;
// MBPrintf("newfile got: %s", cp);
if (*cp == '\r') {
this->SendError("rcp: unexpected <newline>");
return;
}
else if (*cp == 'E') {
this->UpDir();
this->SendOK();
return;
}
else if ((*cp != 'C') && (*cp != 'D')) {
this->SendError("rcp: illegal file type");
return;
}
type = *cp;
cp += 5;
if (*cp++ != ' ') {
this->SendError("rcp: mode not delimited");
return;
}
while (isdigit(*cp))
size = size * 10 + (*cp++ - '0');
fFileSize = size;
fAmtLeft = size;
if (*cp++ != ' ') {
this->SendError("rcp: size not delimited");
return;
}
if (fFileName[0] == 0) {
char namelen = 0;
char* nameptr;
nameptr = (char*) &fFileName[1];
while (*cp != '\r') {
*nameptr++ = *cp++;
namelen++;
}
fFileName[0] = namelen;
}
if (fFileName[1] == '.')
fFileName[1] = '•';
if (this->CreateFile((Str255) fFileName, type)) {
fFileName[0] = 0;
if (type == 'C')
fWorkingOnAFile = true;
this->SendOK();
}
}
void
Rcp::OpenNext()
{
}
void
Rcp::SendOK()
{
tcpWrite(fStreamPtr, "", 1);
}
void
Rcp::SendError(char* msg)
{
WDS(3) wds;
char no = 1;
wds.zero = 0;
wds.block[0].ptr = &no;
wds.block[0].length = 1;
wds.block[1].ptr = msg;
wds.block[1].length = strlen(msg) + 1;
wds.block[2].ptr = "\r";
wds.block[2].length = 1;
tcpWriteWDS(fStreamPtr, (wdsEntry*) &wds);
this->DoQuit();
}
Boolean
Rcp::CreateFile(Str255 name, char type)
{
FSSpec spec;
long dirID;
short refNum;
OSErr theErr = noErr;
FSMakeFSSpec(fVRefNum, fDirID, name, &spec);
if (type == 'C') {
theErr = FSpCreate(&spec, 'MPS ', 'TEXT', smSystemScript);
if ((theErr == noErr) || (theErr == dupFNErr)) {
if (FSpOpenDF(&spec, fsRdWrPerm, &refNum) == noErr) {
fFileIORefNum = refNum;
if (theErr == dupFNErr)
SetEOF(refNum, 0);
}
else
this->SendError("rcp: couldn't open remote file");
}
else
this->SendError("rcp: couldn't create remote file");
}
else {
if ((theErr = FSpDirCreate(&spec, smSystemScript, &dirID)) == noErr) {
HSetVol(nil, fVRefNum, dirID);
fDirID = dirID;
}
else if (theErr == dupFNErr)
this->SendError("rcp: remote directory already exists");
else
this->SendError("rcp: couldn't create remote directory");
}
return (theErr == noErr);
}
void
Rcp::UpDir()
{
short refNum;
long dirID;
HSetVol("\p::", fVRefNum, fDirID);
HGetVol(nil, &refNum, &dirID);
fDirID = dirID;
}
void
Rcp::WriteToFile(char* buf, short len)
{
char* beg = buf;
long cnt = len;
char* end = beg + cnt;
while (beg <= end) {
if (*beg == '\r')
*beg = '\n';
beg++;
}
FSWrite(fFileIORefNum, &cnt, buf);
}
pascal void
Notify( StreamPtr /*tcpStream*/,
unsigned short eventCode,
Ptr userDataPtr,
unsigned short /*termReason*/,
struct ICMPReport* /*icmpMessage*/ )
{
if ((eventCode == TCPTerminate) || (eventCode == TCPClosing)) {
Rcp* rcp = (Rcp*) userDataPtr;
rcp->DoQuit();
WakeUpProcess(&rcp->fPSN);
}
}